home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1995 #5 & #6
/
Amiga Plus CD - 1995 - No. 5 and 6.iso
/
pd
/
serien
/
purity
/
nr.5
/
pascal
/
pcq-programme
/
game
/
game.doc
< prev
next >
Wrap
Text File
|
1995-04-19
|
22KB
|
511 lines
Dokumentation Game.i
--------------------
1. Einleitung
Was macht man (oder Frau), wenn man ein Spiel programmieren will?
Man macht sich schlau! Und warum? Weil nur wenige Leute Informationen
über die Spieleprogrammierung veröffentlichen oder man bekommt
überhaupt keine Infos (so wie ich).
Aber damit ist jetzt Schluß!!!
Warum? Na, ich will euch mit den von mir programmierten Funktionen
und Ideen dazu bewegen, eigene Spiele zu entwickeln.
Ziel ist es, daß die Routinen so leicht wie möglich aufzurufen
sind und so effektiv wie möglich arbeiten.
Ein weiteres Ziel: Jeder soll sie verstehen!!
Und noch ein weiters Ziel: Es ist egal, ob die Routinen in
PCQ-Pascal geschrieben sind oder in Assembler (wobei natürlich
PCQ-Pascal zu bevorzugen ist), hauptsache sie laufen, passen in
das Gesamtkonzept und sind getestet.
Oh Gott, hoffentlich sind das nicht zu hoch gesteckte Ziele, aber
wer weiß, wenn ihr voll mit dabei seit, so ist es kein Problem.
Ich (und auch andere) setzen auf euch !!!
Wenn ihr jetzt denkt, daß ein Spiel in Pascal unmöglich zu schreiben
ist, dann werde ich euch mit meinem ersten Spiel "TakeIt"
überzeugen. Fertig solls Ende Juli '92 sein.
Soweit zum Vorwort. Und was kommt jetzt?
Na, die Erläuterung meiner Routinen und Strukturen aus "Game.i"
natürlich.
Also fangen wir an.
a) Die zu verwendenden Typen, Constanten und Variablen
- ObjektDef
Dieses ist die eigentliche Struktur für die Definition von
Spielobjekten. Wenn ihr genauer hinschaut werdet ihr sehen,
daß sich aus der Graphics.Lib viele Sachen wiederspiegeln
die dort mit den AnimObjekts verwendet werden.
Ich habe bloß keine Lust, das umständliche Handling der
Graphics.Lib zu nutzen inkl. der sehr großen Strukturen.
"Na ist den der verrückt geworden?" werdet ihr jetzt denken.
Nein, ich bin nur jemand, der Wert auf Geschwindigkeit und
Einfachheit legt und deshalb nicht die AnimObjekt-Routinen
nutzt. Die laß ich lieber den Basic-Programmieren übrig
( hiervon kann jeder reden, der mal die Routinen genutzt hat.
Einfach Grauenhaft!!!).
Schaut euch die ObjektDef genau an, ihr werdet sie noch oft
in meinen Routinen sehen.
- Objektsitze
Definiert die Größe eines Objektes in Byte für die Funktion
CollObjekt (siehe unten).
- Objekt
Ist ein Array von max. 256 Objekten. Dient als eigentliche
"Spielwiese" für meine Soielobjekte, da hier alle erforder-
lichen Daten abgelegt sind.
- Picture
Ist wieder ein Kernstück der Routinen. Mit Picture de-
finiere ich mir ein Array mit 20 Images aus Intuition.
Warum denn das?
Nun, um Objekt auf den Bildschirm zu bringen kann man Punkte
verwenden (viel zu aufwendig), Linien (nicht immer zu
gebrauchen), den Zeichensatz (sehr unflexibel), die Bobs
(will ich nicht wegen dem Handling) oder die Images.
Was ist der Vorteil der Images?
Also eins Vorweg: sie werden vom Blitter gezeichnet und sind
deshalb unheimlich schnell auf dem Bildschirm (siehe auch
das Testprogramm). Außerdem muß ich nicht in die Blitter-
programmierung einsteigen.
Und zum anderen sind Images sehr flexibel: die Höhe und
Breite ist vorgebbar, die Anzahl der verwendeten Bitplanes
und, was auch sehr wichtig ist, die verwendeten Farben
lassen sich sehr einfach ansteuern.
Deshalb habe ich mich für die Images entschieden.
In einer zukünftigen Version werde ich vielleicht eine
andere, schnellere Routine verwenden (kennt jemand eine,
die genau das selbe tut, nur schneller?).
- blitctrl
Wird als Globale Variable UNBEDINGT FÜR DIE BLITTERERGEBNISSE
aus der Funktion "Graphcollision" verwendet.
- Blittispeicher
Ja, den müßt ihr selber initialisieren. Und zwar sollte er
so groß sein wie das größte von euch benutzte Objekt ist.
Ansonsten macht der Amiga einen Abgang ......
- MyBitMap
Muß die Adresse der BitMap sein. NICHT die Adresse der
BitPlanes!!!
- MyRPort
Muß der Zeiger auf den dazugehörigen Rastport sein.
Außerdem fehlt noch eine wichtige Sache: die Graphics.Lib MUß VOM
HAUPTPROGRAMM ERÖFFNET SEIN!!! Ansonsten hol's der Guru.....
Schön und gut, das waren erst einmal alle Konstanten, Variablen und
Strukturen. Und was kommt jetzt? Logo, die Funktionen. Wenn ihr
detailierte Informationen haben wollt, so schaut in dem entsprechen-
den Directory nach, sofern dieses vorhanden ist.
b) Die verwendeten Proceduren und Functionen
1) Procedure GraphCollision( x1, y1, xsize, ysize : short);
Diese Funktion testet den rechteckigen Bereich mit den
Eckpunkten x1, y1, x1+xsize, y1+ysize, ob in diesem ein
Punkt gesetz ist.
Aufgerufen wird die Prozedur mit
GraphCollision(x1, y1, xsize, ysize);
Alle Werte müßen vom Typ Short sein. x1 und y1 bezeichnen den
oben links stehenden Punkt in einem Rechteck. Der unten rechts
stehende Punkt wird aus der Addition mit den x- bzw. y-Size
Werten durch das Betriebssystem ermittelt.
Zu beachten ist, daß meine Routinen folgende Globale Werte
im Hauptprogramm voraussetzt:
- MyBitMap ---> Ein Zeiger auf die zu bearbeitende BitMap
( siehe auch das TestProgramm ).
- Graphics.Lib ---> Diese MUß im Hauptprogramm ERFOLGREICH geöffnet
worden sein. Sonst gibts den GURU !
- blitctrl ---> Enthält nach dem Aufruf den Wert 0 (in
dem untersuchten Grfikblock gab es keinen
gesetzten Punkt) oder 1 (es war mind.
ein Punkt gesetzt).
Nach Ende der Prozedur braucht man nur in der Variablen
blitctrl nachzusehen, ob eine Kollision vorgekommen ist!
Recht einfach, oder? Aber es wird noch lustiger:
2) Function CollObjekt(von, bis, x1, y1, x2, y2 : short) : short;
Die Funktion ermittelt, welches Objekt in dem Rechteck
x1, y1, x2, y2 kollidiert ist.
Hierbei kann ein von / bis Bereich für die Objektuntersuchung
angegeben werden (0 - 255 ).
Wird als Von-Wert -1 angegeben, so werden alle Objekte
untersucht und die erste Objektnummer, die zur Kollision
führte, zurück gegeben.
Ist der Rückgabewert -1, so gab es eine Kolision mit einem
nicht definierten Objekt bzw. das Objekt wurde nicht gefunden.
Die Funktion selber untersucht das definierte Array "Objekt"
nach folgendem Schema (tut mir leid, passte nicht auf einen
normalen Bildschirm rauf):
----------------------------------------------------------------------------------------------------
Treffervergleich (O = Objekt, T = Trefferbereich)
Ox1 >= Tx1 und Ox1 =< Tx2 == Ja ==> Oy1 >= Ty1 und Oy1 <= Ty2 == Ja ==> Treffer
! ^ ! ^
! ! ! !
Nein ! Nein !
! ! ! !
V ! V !
Ox2 >= Tx1 und Ox2 =< Tx2 == Ja -+ Oy2 >= Ty1 und Oy2 <= Ty2 == Ja -+
! ^ ! ^
! ! ! !
Nein ! Nein !
! ! ! !
V ! V !
Tx1 >= Ox1 und Tx1 =< Ox2 == Ja -+ Ty1 >= Oy1 und Ty1 <= Oy2 == Ja -+
! ^ ! ^
! ! ! !
Nein ! Nein !
! ! ! !
V ! V !
Tx2 >= Ox1 und Tx2 =< Ox2 == Ja -+ Ty2 >= Oy1 und Ty2 <= Oy2 == Ja -+
! !
! !
Nein Nein
! !
V V
Kein Treffer Kein Treffer
----------------------------------------------------------------------------------------------------
Wer jetzt sagt "Oh Gott, was ist das für eine komplizierte
Abfrage" dem kann ich nur Recht geben. Aber schaut euch
bitte auch das Testprogramm an.
Und wenn das nicht hilft, dann macht es wie ich: malt euch
auf ein Blatt Papier alle Variationsmöglichkeiten, an dem
es Kollisionen zwischen Objekten geben kann (auch zwischen
unterschiedlich großen).
Das Stück hat mich einige Jahre altern lassen!!!
Ganz zu schweigen von der Zeit. Aber ich habe es ausgiebig
getestet, weil mit dieser Routine eine Kollisionserkennung
steht und fällt.
UND SIE STEHT!!!
Sicher, man kann noch einiges zur Beschleunigung tun (auch
wenn sie jetzt schon, wie mir Tests gezeigt haben, sehr
schnell ist), aber ich hatte einfach keine Zeit mehr dafür.
In einem späteren Release werde ich sicherlich noch einige
Minuten dafür verwenden, um sie zu optimieren.
3) Procedure DrawObjekt( VonNr, BisNr : short; MyPlanes,
NotMyPlanes : byte );
Diese Routine zeichnet, unter Verwendung der
DrawImage-Funktion der Intuition.Lib ein oder mehrere
definierte(s) Objekt(e).
Die Variablen "MyPlanes" und "NotMyPlanes" haben
folgende Bedeutung:
- Mit "Myplanes" lege ich fest, in welcher Bitplane die
Picture-Daten gezeichnet werden sollen.
Beispiel:
- Ich habe ein Picture mit 2 Bitplanes
definiert, welches ich auf einem Bild-
schirm mit drei Bitplanes in der 1. und
3. Bitplane zeichnen möchte.
Die Variable "Myplanes" enthält nun für
jede zu zeichnende Bitplane ein Bit. D.H.
für die 1. Plane das Bit 0, für die 2.
Plane das Bit Nr. 1 und so weiter.
In meinem Beispiel muß ich also den Wert
5 vorgeben, da die entsprechende gesetzten
Bits den Wert 5 ergeben.
Alles soweit klar? Na, denn weiter.
- Mit "NotMyplanes" lege ich fest, was mit den
Bitplanes passieren soll, in die ich nicht zeichne.
Setze ich hierbei ein Bit, so wird das Objekt in der
entsprechenden Zeichenfarbe umrandet.
Habt ihrs verstanden? Wenn nicht, dann probiert es einfach
mal aus oder seht euch das entsprechende Testprogramm an.
4) Procedure UnDrawObjekt( VonNr, BisNr : short );
Diese Routine löscht die mit VonNr bis BisNr gekennzeichnete
Objekte auf dem Bildschirm.
Ihr seht, es gibt auch einfache Routinen.
5) Function GetChar() : byte;
Diese Funktion greift direkt auf die Hardwareregister zu und
ermittelt die gedrückte Taste.
Der zurückgegeben Wert ist aber NICHT der ASCII-Wert sondern
vielmehr das Zeichen im "rohen" Format.
Hierzu einige Werte:
- AMIGA-links : $33
- AMIGA-rechts : $31
- DEL : $73
- Cursor hoch : 103
- Cursor runter : 101
- Cursor rechts : 99
- Cursor links : 97
6) Function GetJoy2(): byte;
Diese Funktion fragt über die Hardwareregister den Joystick
am Port 2 ab und gibt folgende Wert zurück:
---> 0 - Joystick wurde nicht berührt
---> 1 - Joystick nach rechts
---> 2 - Joystick nach links
---> 4 - Joystick nach hinten
---> 8 - Joystick nach vorne
---> 16 - Feuertaste gedrückt.
Zu beachten ist, das jeweils nur das entsprechende Bit
gesetzt wird, so das es sehr leicht ist, auch mehrere
Aktionen gleichzeitig abzufragen (z.B. Joystick nach
rechts und hinten und gleichzeitig wurde die Feuertaste
gedrückt).
7) Function ChipCopy( Source : Address; Size : integer)
: Address;
Eine ungeheuer nützlich Funktion (jedenfalls für mich).
Sie allokiert ChipMem in der Größe Size und kopiert die
Daten von der Addresse Source dort hinein.
Zurückgegeben wird die ChipMeM-Adresse für die weitere
Verwendung.
Da eine Programmierung über Pascal zu umständlich war, habe
ich das ganze über Assembler programmiert (siehe Source).
c) So, das wars erstmal. Leider kann ich euch noch kein
Beispielprogramm an die Hand geben, welches alle Routinen
beinhaltet.
Aber wenn ihr euch etwas geduldet werdet ihr mit dem Spiel
"TakeIt" sehen, was sich alles hiermit anstellen läßt.
Nichts desto trotz liegt es an euch, ob ihr nicht auch
entsprechende Routinen schreiben wollt euch
(welche noch zu entwickeln wären steht weiter unten).
Oder setzt euch an eure Freundin und probiert mit den hier
vorgestellten Routinen aus, ob ihr was auf die Beine stellt.
Die Grundausstattung habt ihr und es gilt weiterhin der alte
Spruch: "Jeder ist seines Glückes Schmied".
2. Aufruf, Übergabeparameter
Siehe in der obigen Dokumentation.
3. Einbindung in eigene Programme
Hierzu sind folgende Dinge erforderlich:
a) Im Sourcecode ist die Datei "GAME.I" als Include -File
einzubauen, damit der Compiler auch weiß, was er machen
soll.
b) Der Linkeraufruf ist wie folgt zu modifizieren:
blink <source>.o+GAME.o to <source> library PCQ.lib
4. Erklärung des Source-Codes
Ich glaube, eine Erklärung erübrigt sich, da ich die einzelnen
Schritte dokumentiert habe ( so sollten mal alle Source-Codes
aussehen).
5. Sonstiges
Also fangen wir mal wieder an:
a) Die Funktionen sind ALLE von mir ausreichend getestet
worden. Sie laufen einwandfrei unter der Voraussetzung,
das man für den Rastport eine WindowRastport wählt.
Warum das so ist weiß ich nicht. Ich weiß nur, das alle
Versuche, mit einem ScreenRastport zu arbeiten (wg. der
Ersparnis des gesamten Windowhandlings), mit einer Reise
zum Guru aufgehört haben.
Vielleicht kann mir ja einer von euch sagen, warum dieses
so ist. Ich habs nicht verstanden.
b) Die Zeit, die ich in diese Routinen investiert habe, sehe
ich als sehr groß an (bewegt sich so ca. zwischen 40 - 80
Stunden inkl. aller Test und Abstürze).
Deshalb solltet ihr nach Möglichkeit nicht auch nochmal
versuchen, daß Rad ein zweites Mal zu erfinden! Ich kann
euch nur warnen. Wer nicht gewarnt sein will, den belegt
der Gurumaster mit einer langen Zeit schlafloser Nächte,
vielen Zigaretten (sofern ihr Raucher seid) und jeder
Menge Kaffee (am anderen Morgen).
Die Testzeit habe ich als sehr kritisch angesehen, da ich
der Meinung bin, das nur wirklich ausgetestete Programme
an andere weitergegeben werden sollten.
c) Verbesserungen
O.K., O.K., nicht alle Routinen sind das gelbe vom Ei. Vieles
könnte sicher noch weiter optimiert werden. Wenn ich die
entsprechende Zeit habe werde ich mich auch daran setzen.
Oder wollt ihr dieses vornehmen? Wenn ja, dann schickt mir
doch bitte eine Diskette mit den Änderungen die ihr
vorgenommen habt.
Nur um eins möchte ich euch bitten: bleibt bei der
ObjektDef! Nicht, das ich hierüber das Ja und Amen ausspreche,
aber solange mir keiner sagen kann, warum die Struktur
unbedingt erweitert werden müßte, solltet ihr diese auch
bei euren Programmen nicht weiter verändern.
Falls doch, so laßt uns erstmal darüber diskutiern. Auch ich
kann noch was lernen.
Und denkt bitte dran: eine ausreichende Dokumentation sollte
schon sein, sonst ist keinem damit geholfen, weder dem Ein-
steiger, der verzweifelt ist, weil er den Source nicht lesen
kann, noch der Programmierer, weil er nach 3 Monaten nicht
mehr weiß, wie sein Programm funktionierte.
d) Neuentwicklungen
Ich glaube, hier gibt es noch einiges zu machen als da wären:
1) Eine Soundfunktion
Wäre ich besser auf dem Amiga in Punkto Sound, so
hätte ich auch eine entsprechende Funktion gewählt.
Bin ich aber nicht!
Ich könnte mir aber vorstellen, daß es eine Routine
geben könnte, die im Interrupt läuft und auf Anforderung
Töne von sich geben könnte, wie z.B. Sinusschwingungen,
Explosionen, Schußgeräusche und noch vieles mehr.
Na, Blut geleckt? Dann ran und schreibt die Routine. Bin
gespannt, was dabei rauskommt.
2) DualPlayfields
Um auch einen unabhängigen Hintergrund darstellen zu
können wäre eine Routine erforderlich, welche im
DualPlayFiled-Modus IFF-Bilddaten lädt und diese in
einem entsprechende Screen speichert. Wie's dann
weitergeht, weiß ich nicht.
3) Eine Joystickabfrage für den Port2 bzw. eine
Mausabfrage.
und so weiter, und so weiter.
Ihr seht, es sind keine Grenzen gesetzt.
6. Copyrights
Die Copyrights für diese Routinen liegen bei mir.
( (c) 1992 Jörg Wach )
Ich erlaube allerdings, daß diese Routinen in anderen Programme
eingesetzt werden dürfen, sofern diese nicht für gewerbsmäßige
Zwecke verwendet werden.
Gewerbsmäßig bedeutet, daß die Routinen in einem anderen
Softwareprodukt genutzt oder benutzt werden und dieses
Softwareprodukt gegen einen Geldwert an Dritte verkauft
oder verliehen wird.
In diesem Fall bestehe ich auf die Übersendung einer Kopie
des Programmes sowie auf den Abschluß eines Nutzungsvertrages.
Die Nichtbeachtung kann zu einer strafrechtlichen Verfolgung
führen.
Ich persönlich möchte hiermit keinen abschrecken, der meine Routinen
verwendet und möchte auch nur sehen, was mit meinen Routinen so
passiert, aber bei einer gewerbsmäßigen Verwendung in einem
Produkt betrachte ich es schon als unfair, wenn ich für die
erbrachte Arbeit nicht entlohnt werde, zumal es sich hierbei um
harte Basisarbeit gehandelt hat.
Sollte jemand auf die Idee kommen und die Routinen zu
modifizieren oder zu optimieren so bitte ich doch um die
Übersendung der neuen Routinen. Auch ich kann noch was lernen!
7. Dateiverzeichnis
Folgende Dateien sollte das Gesamtpacket umfassen:
GAME.MOD ---> Der Sourcecode
GAME.I ---> das Includefile
GAME.DOC ---> na was wohl ?
GAME.MOD.o ---> Das entsprechende Objektfile zum einbinden
sowie die entsprechenden Info.-Files und div. Testdateien und
Dokumentationen.
So, nun schreibt mal schön eure Programme mit den Routinen und vergesst
bitte nicht, mir eine Kopie zu schicken (natürlich auf Diskette). Ihr
erhaltet die Diskette mit PD-Soft oder der neuesten SoftWare aus meinen
Fingern zurück.
PCQ, Take it or Break it
JCL Power
Jörg Wach
Waitzstr. 75
W-2300 Kiel 1
Deutschland
30.06.1992